package org.oy.sealogger.common;

import java.util.LinkedList;
import java.util.Observable;
import java.util.Queue;

/**
 * A static, application wide, observable message queue.
 * @author riku
 *
 */
public class MessageQueue extends Observable {

	private static MessageQueue singleton = null;
	
	private Queue<Message> messages;
	private Queue<Message> exceptions;
	
	private MessageQueue() {
		messages = new LinkedList<Message>();
		exceptions = new LinkedList<Message>();
	}
	
	/**
	 * Adds an info message to the queue. Info messages are shown if there are no warnings or errors
	 * in the queue.
	 * @param source A descriptive name of the message source
	 * @param message
	 */
	public void info(String source, String message) {
		addMessage(new Message(source, message, Message.MessageType.INFO));
	}
	
	/**
	 * Adds a warning message to the queue. Warning messages will be priorised to info messages.
	 * @param source A descriptive name of the message source
	 * @param message
	 */
	public void warning(String source, String message) {
		addMessage(new Message(source, message, Message.MessageType.WARNING));
	}
	
	/**
	 * Adds an error message to the queue. Error messages are always priorised in presentation order.
	 * @param source A descriptive name of the message source
	 * @param message
	 */
	public void error(String source, String message) {
		addMessage(new Message(source, message, Message.MessageType.ERROR));
	}
		
	private void addMessage(Message message) {
		if(message.getType() == Message.MessageType.ERROR)
			exceptions.add(message);
		else
			messages.add(message);
		
		synchronized(this) {
			setChanged();
			notifyObservers();
		}
	}
	
	/**
	 * Reads a message from the queue and destroys it
	 * @return
	 */
	public Message consumeMessage() {
		if(!exceptions.isEmpty())
			return exceptions.poll();
		else if(!messages.isEmpty())
			return messages.poll();
		else
			return null;
	}
	
	/**
	 * Reads a message from the queue without destroying it, ergo the next message query will
	 * give the same result as the previous one.
	 * @return
	 */
	public Message getMessage() {
		if(!exceptions.isEmpty())
			return exceptions.peek();
		else if(!messages.isEmpty())
			return messages.peek();
		else
			return null;
	}
	
	/**
	 * Get the instance of the class.
	 * @return
	 */
	public static MessageQueue getInstance() {
		if(singleton == null)
			singleton = new MessageQueue();
		
		return singleton;
	}
}
